package com.springboot.usercenter.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.springboot.usercenter.mapper.UserMapper;
import com.springboot.usercenter.model.UserInfo;
import com.springboot.usercenter.model.constant.UserConstant;
import com.springboot.usercenter.model.dto.DeleteUserDTO;
import com.springboot.usercenter.model.dto.SearchUserListDTO;
import com.springboot.usercenter.model.dto.UserLoginDTO;
import com.springboot.usercenter.model.dto.UserRegisterDTO;
import com.springboot.usercenter.model.request.UserRegisterParam;
import com.springboot.usercenter.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.scanner.Constant;

import java.lang.constant.Constable;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * Description :
 * User: jiume
 * Date: 2025-04-23
 * Time: 13:59
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @SneakyThrows
    @Override
    public UserRegisterDTO userRegister(String userAccount, String userPassword, String checkPassword) {
        // 1、校验参数
        // 账号、密码不能为空
        if (!StringUtils.hasText(userAccount) || !StringUtils.hasText(userPassword)
                || !StringUtils.hasText(checkPassword)) {
            log.info("[userRegister] 账号或密码或确认密码为空");
            return new UserRegisterDTO((long)-1, "账号或密码或确认密码为空");
        }
        // 账号。密码的长度不能少于6位
        if (userAccount.length() < 6 || userPassword.length() < 6
                || checkPassword.length() < 6) {
            log.info("[userRegister] 账号或密码或确认密码 少于6位");
            return new UserRegisterDTO((long)-1, "账号或密码或确认密码 少于6位");
        }
        // 账号不能包含特殊字符
        // 使用正则表达式进行处理

        //^代表否定，匹配除了数字、字母、下划线的特殊字符。
        String SPECIAL_CHAR_PATTERN = "[^a-zA-Z0-9_]";
        Pattern pattern = Pattern.compile(SPECIAL_CHAR_PATTERN);
        Matcher matcher = pattern.matcher(userAccount);
        // 如果 find() 返回 true，说明包含特殊字符
        if (matcher.find()) {
            log.info("[userRegister] 账号包含特殊字符");
            return new UserRegisterDTO((long)-1, "账号包含特殊字符");
        }
        // 密码 和 确认密码是否一致
        if (!checkPassword.equals(userPassword)) {
            log.info("[userRegister] 密码和确认密码不一致");
            return new UserRegisterDTO((long)-1, "密码和确认密码不一致");
        }
        // 查询账号是否已经存在
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        Long result = userMapper.selectCount(queryWrapper);
        if (result > 0) {
            log.info("[userRegister] 账号已经存在，无法注册");
            return new UserRegisterDTO((long)-1, "账号已经存在，无法注册");
        }

        // 2、对 密码 进行加密处理
        String newUserPassword = userPassword + UserConstant.ENCRYPT_SALT;
        String encryptStr = DigestUtils.md5DigestAsHex(newUserPassword.getBytes());
        // 3、将 用户信息 存储到数据库中
        UserInfo userInfo = new UserInfo();
        userInfo.setUserAccount(userAccount);
        userInfo.setUserPassword(encryptStr);
        userInfo.setUserIdentity(0); // 默认都是普通用户
        int resultInsert = userMapper.insert(userInfo);
        if (resultInsert < 0) {
            log.info("[userRegister] 用户新增失败");
            return new UserRegisterDTO((long)-1, "用户新增失败");
        } else {
            log.info("[userRegister] 用户新增成功");
            return new UserRegisterDTO(userInfo.getId(), "用户新增成功");
        }
    }

    @Override
    public UserLoginDTO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 1、校验参数是否合法
        // 判断用户账号、密码是否为空
        if (!StringUtils.hasText(userAccount) || !StringUtils.hasText(userPassword)) {
            log.info("[userLogin] 账号或密码为空");
            return new UserLoginDTO(null, "账号或密码为空");
        }
        // 判断用户账号和密码的长度是否符合要求
        if (userAccount.length() < 6 || userPassword.length() < 6) {
            log.info("[userLogin] 账号或密码长度少于6位");
            return new UserLoginDTO(null, "账号或密码长度少于6位");
        }
        // 判断用户账号是否包含特殊字符
        //^代表否定，匹配除了数字、字母、下划线的特殊字符。
        String SPECIAL_CHAR_PATTERN = "[^a-zA-Z0-9_]";
        Pattern pattern = Pattern.compile(SPECIAL_CHAR_PATTERN);
        Matcher matcher = pattern.matcher(userAccount);
        // 如果 find() 返回 true，说明包含特殊字符
        if (matcher.find()) {
            log.info("[userLogin] 账号包含特殊字符");
            return new UserLoginDTO(null, "账号包含特殊字符");
        }
        // 2、查询用户是否存在以及用户的密码是否正确 (查询数据库)
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        // 由于在注册阶段将用户账号设置为了唯一的，因此这里只能查出一个或者0个
        UserInfo userInfo = userMapper.selectOne(queryWrapper);
        // 判断 该用户账号 是否存在
        if (userInfo == null) {
            log.info("[userLogin] 账号不存在");
            return new UserLoginDTO(null, "账号不存在");
        }
        // 判断密码是否正确
        // 将输入的密码进行加密处理
        String newUserPassword = userPassword + UserConstant.ENCRYPT_SALT;
        String encryptStr = DigestUtils.md5DigestAsHex(newUserPassword.getBytes());
        if (encryptStr.equals(userInfo.getUserPassword())) {
            // 用户登录成功
            // 将用户信息进行脱敏操作，存储到 session 中
            HttpSession session = request.getSession();
            userInfo.setUserPassword("");
            session.setAttribute("USER_LOGIN_STATUS", userInfo);
            log.info("[userLogin] "+userAccount+" 登录成功");
            return new UserLoginDTO(userInfo, "登录成功");
        } else {
            log.info("[userLogin] 密码错误");
            return new UserLoginDTO(null, "密码错误");
        }
    }

    @Override
    public SearchUserListDTO searchUserList(String username, HttpServletRequest request) {
        // 注意，这里是允许 username 为空，从而去查询所有用户信息的
        // 1、鉴权——判断调用当前接口的用户是否为管理员
        if (!isSafety("searchUserList", request)) {
            return new SearchUserListDTO(null, "用户无权进行此操作");
        }
        // 2、根据 用户名 去模糊查询
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username", username);
        log.info("[searchUserList] 查询成功: "+"查询的username为: "+username);
        return new SearchUserListDTO(userMapper.selectList(queryWrapper), "查询成功");
    }

    @Override
    public DeleteUserDTO deleteUser(Long id, HttpServletRequest request) {
        // 1、校验参数是否合法
        // 判断 Id 的值 是否大于0
        if (id <= 0) {
            log.info("[deleteUser] id < 0");
            return new DeleteUserDTO(false, "id < 0");
        }
        // 2、鉴权——只有超级管理员才能执行下面的操作
        if (!isSafety("deleteUser", request)) {
            return new DeleteUserDTO(false, "用户无权进行此操作");
        }
        // 3、进行逻辑删除
        int result = userMapper.deleteById(id);
        if (result > 0) {
            log.info("[deleteUser] 删除成功，删除的用户Id为: "+id);
            return new DeleteUserDTO(true, "删除成功");
        } else {
            log.info("[deleteUser] 删除失败，删除的用户Id为: "+id);
            return new DeleteUserDTO(false, "删除失败");
        }
    }

    /**
     * 鉴权 —— 判断当前用户是否为管理员
     * @param methodName 调用的方法，方便后续打印日志
     * @param request HttpServletRequest
     * @return 如果是管理员，返回true；反之，则返回false
     */
    private boolean isSafety(String methodName, HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            log.info("["+methodName+"] 用户未登录");
            return false;
        }
        UserInfo userInfo = (UserInfo) session.getAttribute(UserConstant.USER_LOGIN_STATUS);
        if (userInfo == null) {
            log.info("["+methodName+"] 用户未登录");
            return false;
        }
        if (userInfo.getUserIdentity() != 1) {
            // 只要不是管理员，一律拦截
            log.info("["+methodName+"] "+userInfo.getUserAccount()+"用户非管理员");
            return false;
        }
        return true;
    }
}
